#pragma once

#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <pthread.h>
#include <functional>
#include <unordered_map>

#include "ThreadPool.hpp"
#include "InetAddr.hpp"
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"
// #include "Task.hpp"

const static int default_backlog = 5; // TODO
using task_t = function<void()>;
using callback_t = function<void(int, InetAddr &)>; // 回调

class TcpServer;

// class ThreadData
// {
// public:
//     ThreadData(int sock, TcpServer *t,struct sockaddr_in &peer)
//     : sockfd(sock), svr_ptr(t),addr(peer)
//     {
//     }
//     int Sockfd()
//     {
//         return sockfd;
//     }
//     TcpServer *GetServer()
//     {
//         return svr_ptr;
//     }
//     ~ThreadData()
//     {
//         close(sockfd);
//     }

// private:
//     int sockfd;
//     TcpServer *svr_ptr;
// public:
//     InetAddr addr;
// };

class TcpServer : nocopy
{
public:
    TcpServer(uint16_t port)
        : _port(port), _isrunning(false)
    {
    }
    void Init()
    {
        // 1.创建
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            lg.LogMessage(Fatal, "创建套接字失败: %d,error string: %s\n", errno, strerror(errno));
            exit(Fatal);
        }
        lg.LogMessage(Debug, "创建套接字成功: sockfd: %d", _listensock);

        // 解决绑定失败的问题
        int opt = 1;
        setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

        // 2.填充本地(local)网络信息并bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        // 2.1 bind
        if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) != 0)
        {
            lg.LogMessage(Fatal, "bind套接字失败: %d,error string: %s\n", errno, strerror(errno));
            exit(Bind_Err);
        }
        lg.LogMessage(Debug, "bind套接字成功: sockfd: %d", _listensock);

        // 3.设置socket为监听状态，tcp特有
        if (listen(_listensock, default_backlog) != 0)
        {
            lg.LogMessage(Fatal, "监听套接字失败: %d,error string: %s\n", errno, strerror(errno));
            exit(Listen_Err);
        }
        lg.LogMessage(Debug, "监听套接字成功: sockfd: %d\n", _listensock);
        TreadNs::ThreadPool<task_t>::GetInstance()->Start();
    }

    // 启动
    // void Service(int sockfd)
    // {
    //     char buff[1024];
    //     while (true)
    //     {
    //         ssize_t n = read(sockfd, buff, sizeof(buff) - 1); // 读进来
    //         if (n > 0)
    //         {
    //             buff[n] = 0;
    //             cout << "客户端：" << buff << endl;
    //             string echo_string = "server#:";
    //             echo_string += buff;
    //             write(sockfd, echo_string.c_str(), echo_string.size()); // 写出去
    //         }
    //         else if (n == 0) // 返回值为0，表示对端关闭了连接
    //         {
    //             lg.LogMessage(Info, "对端关闭了连接\n");
    //             break;
    //         }
    //         else
    //         {
    //             lg.LogMessage(Info, "读消息失败： %d,error string: %s\n", errno, strerror(errno));
    //             break;
    //         }
    //     }
    // }
    void Service(int sockfd, InetAddr &addr)
    {
        char buff[1024];
        while (true)
        {
            ssize_t n = read(sockfd, buff, sizeof(buff) - 1); // 读进来
            if (n > 0)
            {
                buff[n] = 0;
                cout << addr.PrintDebug() << "# " << buff << endl;
                string echo_string = "server#:";
                echo_string += buff;
                write(sockfd, echo_string.c_str(), echo_string.size()); // 写出去
            }
            else if (n == 0) // 返回值为0，表示对端关闭了连接
            {
                lg.LogMessage(Info, "对端关闭了连接\n");
                break;
            }
            else
            {
                lg.LogMessage(Info, "读消息失败： %d,error string: %s\n", errno, strerror(errno));
                break;
            }
        }
    }
    // 处理请求
    // static void *HandlerRequest(void *args)
    // {
    //     ThreadData *td = static_cast<ThreadData *>(args);
    //     // pthread_detach用于将指定的线程设为“分离状态”。分离状态的线程在结束时会自动释放其资源，而不需要其他线程调用 pthread_join() 来回收资源。
    //     pthread_detach(pthread_self()); // 意思是将当前线程设为分离状态
    //     td->GetServer()->Service(td->Sockfd(),td->addr);
    //     delete td;
    //     return nullptr;
    // }
    void Start()
    {
        _isrunning = true;
        signal(SIGCHLD, SIG_IGN); // 对应v3.多进程（信号），在linux中如果对SIGCHLD忽略，子进程退出的时候，自动释放自己的资源
        while (_isrunning)
        {
            // 4. 获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensock, (struct sockaddr *)&peer, &len); // 连接

            if (sockfd < 0)
            {
                lg.LogMessage(Warning, "获取套接字失败: %d,error string: %s\n", errno, strerror(errno));
                continue;
            }
            lg.LogMessage(Debug, "获取套接字成功: sockfd: %d", sockfd);
            // 5. 提供服务 v1~v4/////////////////////////////////////////
            // v1
            // Service(sockfd);
            // close(sockfd);

            // v2.多进程
            // pid_t id = fork();
            // if (id < 0)
            // {
            //     close(sockfd);
            //     continue;
            // }
            // else if (id == 0)
            // {
            //     // child
            //     close(_listensock);
            //     if (fork() > 0)
            //         exit(0);
            //     // 孙子进程  （孤儿进程）正常处理
            //     Service(sockfd);
            //     close(sockfd);
            //     exit(0);
            // }
            // else
            // {
            //     close(sockfd);
            //     pid_t rid = waitpid(id, nullptr, 0);
            //     if (rid == id)
            //     {
            //         //
            //     }
            // }
            // v3.多进程（信号）
            // pid_t id = fork();
            // if (id < 0)
            // {
            //     close(sockfd);
            //     continue;
            // }
            // else if (id == 0)
            // {
            //     // child
            //     close(_listensock);
            //     Service(sockfd);
            //     close(sockfd);
            //     exit(0);
            // }
            // else
            // {
            //     close(sockfd);
            // }
            // v4.多线程（客户端来了才创建线程，效率不高）
            // ThreadData *td = new ThreadData(sockfd, this,peer);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, HandlerRequest, td);
            // 不需要关闭fd描述符，共享
            //
            // v5.线程池
            InetAddr addr(peer);
            task_t t = bind(&TcpServer::Routine, this, sockfd, addr);
            TreadNs::ThreadPool<task_t>::GetInstance()->Push(t);
        }
    }
    string Read(int sockfd)
    {
        char type[1024];
        ssize_t n = read(sockfd, type, sizeof(type) - 1); // 读进来
        if (n > 0)
        {
            type[n] = 0;
        }
        else if (n == 0) // 返回值为0，表示对端关闭了连接
        {
            lg.LogMessage(Info, "对端关闭了连接\n");
        }
        else
        {
            lg.LogMessage(Info, "读消息失败： %d,error string: %s\n", errno, strerror(errno));
        }
        return type;
    }

    void Routine(int sockfd, InetAddr &addr)
    {
        string type = Read(sockfd);
        lg.LogMessage(Debug,"%s select %s \n",addr.PrintDebug(),type.c_str());
        if (type == "ping")
        {
            funcs[type](sockfd, addr);
        }
        else if (type == "translate")//翻译
        {
            funcs[type](sockfd, addr);
        }
        else if (type == "transform")//转换
        {
            funcs[type](sockfd, addr);
        }
        else
            funcs["default"](sockfd, addr);
        
        close(sockfd);
    }
    // 登记/注册
    void RegisterFunc(const string &name, callback_t func)
    {
        funcs[name] = func;
    }

    ~TcpServer()
    {

    }

private:
    uint16_t _port;
    int _listensock;
    bool _isrunning;

    // 构建业务逻辑
    unordered_map<string, callback_t> funcs;
};